<?php
defined('PLUGINFRAME') or exit('hacking attempt');

class Db extends Object{
    public $memKey='';
    

    public function insert($data,$options){
        $sql="INSERT INTO {$options['table']}(".implode(',', array_keys($data)).') VALUES ('.implode(',', array_fill(0, count($data), '?')).');';
        $values=array_values($data);
        $this->memKey=$this->oriSql($sql,$values);
        $this->query($sql,$values);
        return $this->getLastInsertId();
    }

    /*
     * 拼接where条件语句,为了兼容PDO,$where只能为数组
     * @param array $where
     * */
    private function _where($where,&$result){
        if (is_array($where)){  //控制连接条件括号闭合如,()and()
            static $switch=0;
            static $deep=1;//嵌套的深度
            $filter=array('in');
            $result=array('sql'=>'','value'=>'');//先声明再使用
            $logic=isset($where['_logic'])?$where['_logic']:'and';
            unset($where['_logic']);
            foreach ($where as $wKey=>$wVal){
                if (is_array($wVal) && !in_array($wKey, $filter)){
                    $result['sql'].='(';
                    $switch++;
                    $deep++;
                    $this->_where($wVal, $result);
                }else{
                    switch ($wKey){
                        case 'in':
                            $in=0;
                            $fpk='';
                            //数组的键为键名元素为键值;字符串第一位都是键名后面是键值
                            if (is_array($wVal)){
                                $wVal=each($wVal);
                                $fpk=$wVal['key'];
                                $wVal=explode(',', $wVal['value']);
                                $in=count($wVal);
                            }else if (strpos($wVal, ',')!==false){
                                $wVal=explode(',', $wVal);
                                $fpk=array_shift($wVal);
                                $in=count($wVal);
                            }
                            $in=array_fill(0, $in, '?');
                            $result['sql'].=$fpk.' in('.implode(',', $in).') '.$logic.' ';
                            foreach ($wVal as $wV)
                                $result['value'][]=$wV;
                            break;
                        default:
                          $result['sql'].=$wKey.'=? '.$logic.' ';
                          $result['value'][]=$wVal;
                          break;
                    }
                }
            }
            $result['sql']=rtrim($result['sql'],$logic.' ');
            if ($switch){
                $result['sql'].=')';
                $switch--;
            }
            --$deep;
            if ($deep==0){
                $result['sql']=' WHERE '.$result['sql'];
                $deep=1;
            }
        }
        return false;
    }
    
    public function select($opts,$multirow=true){
        if (!empty($opts['where'])){
            $value=array();
            if ($this->_where($opts['where'], $value)!==false);
                $opts['where']=$value['sql'];
        }
        
        if (!empty($opts['orderby'])) {
            //为了简单化不支持数组形式
            $opts['orderby']=is_array($opts['orderby']) ?'':' order by '.$opts['orderby'];
        }
        if (!empty($opts['join'])){
            $this->_join($opts['join']);
        }
        
        $pageVal=array();
        if (!empty($opts['limit'])){
        	$pageVal=$value['value'];
        	$value['value']=array_merge($value['value'],$opts['limit']);
        	$opts['limit']=' limit '.implode(' , ', array_fill(0, count($opts['limit']), '?'));
        }
        
        if (!empty($opts['limit'])){
        	$pageSql=$this->replaceSql(array_merge($opts,array('limit'=>'')));
        	$this->query($pageSql,isset($pageVal)?$pageVal:array());
        	$counts=$multirow?$this->fetchAll():$this->fetch();
        	$this->records=count($counts);
        }
        $sql=$this->replaceSql($opts);
        if (isset($value['value'])){
            $this->memKey=$this->oriSql($sql, $value['value']);
        }else {
            $this->memKey=$sql;
        }
        $this->query($sql,isset($value['value'])?$value['value']:array());
        return $multirow?$this->fetchAll():$this->fetch();
    }
    /*
     * @param bool $multirow 为true取多条记录为false去一条记录
     * 
     * */
    public function select2($opts=array(),$multirow=true){
        $value=array();
        if (isset($opts['where']) && !empty($opts['where'])){
            $this->_where($opts['where'], $value);
            $opts['where']=$value['sql'];
        }
        $opts['orderby'] && $opts['orderby']=' order by '.$opts['orderby'];
        
        isset($opts['where']) || $opts['where']='';
        isset($opts['orderby']) || $opts['orderby']='';
        isset($opts['group']) || $opts['group']='';
        isset($opts['having']) || $opts['having']='';
        isset($opts['limit'])  || $opts['limit']='';
        $sql="SELECT {$opts['field']} FROM {$opts['table']} ".$opts['where'].$opts['group'].$opts['having'].$opts['orderby'].$opts['limit'];
        $this->memKey=$this->oriSql($sql, $value['value']);
        $this->query($sql,$value['value']);
        return $multirow?$this->fetchAll():$this->fetch();
        
    }
    
    //关联操作
    public function r_select($opt=array(),$multirow=true){
        $this->_pri=isset($opt['pk'])?$opt['pk']:$this->_pri;
        $join=$opt['join'];
        $opt['join']='';
        $pris=array();
        $one=$this->select($opt);
        foreach ($one as $v)
            $pris[]=$v[trim($this->_pri)]; 
        $new=array();
        foreach ($join as $jkey=>$jval){
            if (isset($jval['sub']) && is_array($jval['sub'])){
            	//左关联
                //$new=array();
                $opt['field']=$jval['field'];
                $opt['orderby']=$jval['sub']['orderby'];
                $opt['table']='';
                
                foreach ($one as $k=>$v){
                	$w=array_merge($jval['sub']['where'],array($jval['fpk']=>$v[$this->_pri]));
                    $opt['where']=$w;
                	$two=empty($opt['limit'])?D($jval['table'])->select($opt):D($jval['table'])->select(array_merge($opt,array('limit'=>'')));
                	
                	if (isset($new[$k][$this->_pri])){//var_dump($two);exit('end');
                	   $new[$k][$jval['sub']['index']]=$two;
                	}else{
                	   $v[$jval['sub']['index']]=$two;
                	   $new[]=$v;
                	}
                }
               
            }else{
                $spris=array();
                //$new=array();
                if (isset($jval['sub']) && is_string($jval['sub'])){
                    //左关联
                    foreach ($one as $v)
                        $spris[]=$v[$jval['sub']];
                    $opt['field']=$jval['field'];
                    $opt['where']=array('in'=>$jval['fpk'].','.implode(',', $spris));
                    $opt['table']='';
                    $two=empty($opt['limit'])?D($jval['table'])->select($opt):D($jval['table'])->select(array_merge($opt,array('limit'=>'')));
                    $i=0;
                    foreach ($one as $row){
                        foreach ($two as $read){
                            if ($row[$this->_pri]==$read[$jval['fpk']]){
                                foreach ($read as $rk=>$rv){
                                    if (array_key_exists($rk, $row))
                                        $row[$jval['table'].'_'.$rk]=$rv;
                                    else 
                                        $row[$rk]=$rv;
                                }
                              $new[$i]=$row;
                              break;
                            }
                        }
                        if (!isset($new[$i]) || empty($new[$i])){
                            $new[$i]=$one[$i];
                        }
                        $i++;
                    }
                }else {
                    //右关联
//                    $tmpOpt='';
//                    if (!empty($opt['limit']))
//                       $tmpOpt=$opt['limit'];
                    $one=empty($opt['limit'])?$this->select($opt):$this->select(array_merge($opt,array('limit'=>'')));
                    foreach ($one as $v)
                        $spris[]=$v[$this->_pri];
                    $opt['field']=$jval['field'];
                    $opt['where']=array('in'=>$jval['fpk'].','.implode(',', $spris));
                    $opt['table']='';
                    $two=D($jval['table'])->select($opt);
                    foreach ($two as $read){
                        foreach ($one as $row){
                            if ($row[$this->_pri]==$read[$jval['fpk']]){
                                foreach ($read as $rk=>$rv){
                                    if (array_key_exists($rk, $row))
                                        $row[$jval['table'].'_'.$rk]=$rv;
                                    else 
                                        $row[$rk]=$rv;
                                }
                                $new[]=$row;
                            }
                        }
                    }
                }
            }
        }
        return $new;
    }
    
    //替换sql语句
    private function replaceSql($replace){
        //SELECT %DISTINCT% %FIELD% FROM %TABLE% %JOIN% %WHERE% %GROUP% %HAVING% %ORDERBY% %LIMIT% %UNION%
        $map=array('distinct'=>'%DISTINCT%','field'=>'%FIELD%','table'=>'%TABLE%','join'=>'%JOIN%','where'=>'%WHERE%',
                       'group'=>'%GROUP%','having'=>'%HAVING%','orderby'=>'%ORDERBY%','limit'=>'%LIMIT%','union'=>'%UNION%');
        $search=array_values($map);
        $rep=array();
        $f=array_keys($map);
        foreach ($f as $fVal)
            $rep[]=$replace[$fVal];
        
        return str_replace($search,$rep,$this->selectSql);
    }
    
    /*
     * 完整的sql语句,方便调试
     * */
    private function oriSql($sql,$values){
        foreach ($values as $key=>$val)
            $values[$key]=addslashes($val);
        if (strpos($sql, '%s')!==false)return false;
        $sql=str_replace('?', '%s', $sql);
        array_unshift($values, $sql);
        return call_user_func_array('sprintf', $values);
    }
    
    public function update($opts){
        $tmp_sql='';
        $values=array();
        $this->_where($opts['where'],$values);
        $opts['where']=$values['sql'];
/*        foreach ($opts['data'] as $opKey=>$opVal){
            $tmp_sql.=$opKey.'=? and ';
            $values[]=$opVal;
        }*/
//        $opts['where']=rtrim($tmp_sql,'and ');
        $sql='UPDATE '.$opts['table'].' SET '.implode('=?,', array_keys($opts['data'])).'=? '.$opts['where'];
        $this->query($sql,array_merge(array_values($opts['data']),$values['value']));
        return $this->getAffectRows();
    }
    
    //删除
    public function delete($opts){
        $values=array();
        $this->_where($opts['where'],$values);
        $opts['where']=$values['sql'];
        $sql='DELETE FROM '.$opts['table'].$opts['where'];
        $this->query($sql,$values['value']);
        return $this->getAffectRows();
    }
    
    public function setAttr($value){
        $this->fetchMode=$value;
    }

    private function _join($joinOpt){
        foreach ($joinOpt as $jOpt){
            //
        }
    }
    
    public function getPageCount(){
    	return $this->records;
    }
    
}